﻿Imports System.Threading

Namespace ReaderWriterLockWrapper
	''' <summary>
	'''   A wrapper to handle ReaderWriterLock functionality using ReadWriteLocker.
	'''   NHL stands for Non-Hard Locking.
	''' </summary>
	''' <remarks></remarks>
	Public Class NHLReaderWriterLock
		Inherits ReadWriteLocker

		#Region "Constructors"
			Public Sub New()
				MyBase.New(Behavior.ThrowOnDeadLocks)
			End Sub
		#End Region

		#Region "Properties"
			Public ReadOnly Property IsReaderLockHeld As Boolean
				Get
					Return IsReading
				End Get
			End Property

			Public ReadOnly Property IsWriterLockHeld As Boolean
				Get
					Return IsWriting
				End Get
			End Property

			Public ReadOnly Property WriterSeqNum As Integer
				Get
					Return -1
				End Get
			End Property
		#End Region

		#Region "Methods"
			''' <summary>
			'''   If millisecondsTimeout is 0 then this performs a TryGetReadLock().
			'''     Otherwise, it does a regular GetReadLock, ignoring the timeout
			'''     value specified.
			''' </summary>
			''' <remarks>
			'''   Since this locking mechenism can never hard lock, timing out only
			'''     adds complexity and overhead.
			''' 
			'''   In most cases using a time out is to prevent hard locks from being
			'''     perminent.  But this leads to unneeded guess work and can defeate
			'''     thread safety.
			''' 
			'''   Using timeouts for different purposes than thread safety is not
			'''     supported, as my ReadWriteLocker is only designed to facilitate
			'''     thread safety, and that is a feature not related to thread safety.
			''' 
			'''   Please fill in a feature request on nohardlockrwlocker.codeplex.com
			'''     if you would like this feature anyways.
			''' </remarks>
			Public Sub AquireReaderLock(millisecondsTimeout As Integer)
				If millisecondsTimeout = 0 Then
					TryLockForReading()
				Else
					LockForReading()
				End If
			End Sub

			Public Sub AquireReaderLock(timeout As TimeSpan)
				If timeout.TotalMilliseconds = 0 Then
					TryLockForReading()
				Else
					LockForReading()
				End If
			End Sub

			''' <summary>
			'''   If millisecondsTimeout is 0 then this performs a TryGetWriteLock().
			'''     Otherwise, it does a regular GetWriteLock, ignoring the timeout
			'''     value specified.
			''' </summary>
			''' <remarks>
			'''   Since this locking mechenism can never hard lock, timing out only
			'''     adds complexity and overhead.
			''' 
			'''   In most cases using a time out is to prevent hard locks from being
			'''     perminent.  But this leads to unneeded guess work and can defeate
			'''     thWrite safety.
			''' 
			'''   Using timeouts for different purposes than thWrite safety is not
			'''     supported, as my WriteWriteLocker is only designed to facilitate
			'''     thWrite safety, and that is a feature not related to thWrite safety.
			''' 
			'''   Please fill in a feature request on nohardlockrwlocker.codeplex.com
			'''     if you would like this feature anyways.
			''' </remarks>
			Public Sub AquireWriterLock(millisecondsTimeout As Integer)
				If millisecondsTimeout = 0 Then
					TryLockForWriting()
				Else
					LockForWriting()
				End If
			End Sub

			Public Sub AquireWriterLock(timeout As TimeSpan)
				If timeout.TotalMilliseconds = 0 Then
					TryLockForWriting()
				Else
					LockForWriting()
				End If
			End Sub

			Public Function UpgradeToWriterLock(millisecondsTimeout As Integer) As LockCookie
				AquireWriterLock(millisecondsTimeout)

				Return New LockCookie()
			End Function

			Public Function UpgradeToWriterLock(timeout As TimeSpan) As LockCookie
				AquireWriterLock(timeout)

				Return New LockCookie()
			End Function

			Public Sub RestoreLock(ByRef cookie As LockCookie)
			End Sub

			Public Sub DowngradeFromWriterLock(ByRef cookie As LockCookie)
				ReleaseWriterLock()
			End Sub

			Public Sub ReleaseReaderLock()
				UnlockForReading()
			End Sub

			Public Sub ReleaseWriterLock()
				UnlockForWriting()
			End Sub

			''' <summary>
			'''   This doesn't do anything.  As of now this is because it is
			'''     out-of-scope (reducing thread safety).
			''' 
			'''   But in the future this could change all write locking to
			'''     read locking.  I'm not 100% sure, but maybe this would
			'''     allow similar functionality of having multiple threads
			'''     run at once?
			''' </summary>
			Public Function ReleaseLock() As LockCookie
				Return New LockCookie()
			End Function

			''' <summary>
			'''   This returns true, as I don't keep track of whether writing
			'''     has occurred.  This shouldn't be a feature of the locker,
			'''     because maybe writing happened without using a write lock,
			'''     or write locking did occur, but not for the specific object
			'''     in question.
			''' 
			'''   Therefore, it is up to the application to track this.
			''' </summary>
			Public Function AnyWritersSince(seqNum As Integer) As Boolean
				Return True
			End Function
		#End Region
	End Class
End Namespace
